#include <odbc/connection.hpp>
#include <odbc/environment.hpp>
#include <odbc/odbc_error.hpp>
#include <sstream>

namespace odbc
{

connection::connection( 
		const environment& env, 
		const std::string& connectionString, 
		unsigned int timeOut,
		bool hasAutocommit)
	: handle_( SQL_NULL_HANDLE)
{
	try
	{
		// Allocate the handle
		odbc_error::check_success(
			SQLAllocHandle( SQL_HANDLE_DBC, env.handle_, &handle_),
			env);
		// Set the access mode to read-write.
		odbc_error::check_success(
			SQLSetConnectAttr( 
					handle_, 
					SQL_ATTR_ACCESS_MODE, 
					SQLPOINTER( SQL_MODE_READ_WRITE), 
					SQL_IS_UINTEGER),
			*this);

		this->set_autocommit( hasAutocommit);
		
#ifdef _MSC_VER
#pragma warning( push)
#pragma warning( disable: 4312)
#endif
		// Set the timeout
		odbc_error::check_success( 
			SQLSetConnectAttr( 
					handle_, 
					SQL_ATTR_CONNECTION_TIMEOUT, 
					SQLPOINTER( SQLUINTEGER( timeOut)), 
					SQL_IS_UINTEGER),
			*this);
#ifdef _MSC_VER
#pragma warning( pop)
#endif
		// Open the connection
		odbc_error::check_success( 
			SQLDriverConnect( 
					handle_, 
					NULL, 
					(SQLCHAR*)connectionString.c_str(), 
					(SQLSMALLINT)connectionString.size(),
					NULL, 0, NULL, 
					SQL_DRIVER_NOPROMPT),
			*this);

	}
	catch( ...)
	{
		SQLFreeHandle( SQL_HANDLE_DBC, handle_);
		throw;
	}
}


connection::~connection() throw()
{
	if( SQL_NULL_HANDLE != handle_)
	{
		SQLDisconnect( handle_);
		SQLFreeHandle( SQL_HANDLE_DBC, handle_);
	}
}

void connection::set_autocommit( bool on)
{
	odbc_error::check_success( 
		SQLSetConnectAttr( 
				handle_, 
				SQL_ATTR_AUTOCOMMIT, 
				(SQLPOINTER)on, 
				SQL_IS_UINTEGER),
		*this);
}


void connection::commit()
{
	odbc_error::check_success(
		SQLEndTran( 
			SQL_HANDLE_DBC,
			handle_,
			SQL_COMMIT),
		*this);
}


void connection::rollback()
{
	odbc_error::check_success(
		SQLEndTran( 
			SQL_HANDLE_DBC,
			handle_,
			SQL_ROLLBACK),
		*this);
}


bool connection::autocommit() const
{
	SQLUINTEGER value = 0;
	SQLINTEGER dummyLen = 0;

	odbc_error::check_success(
		SQLGetConnectAttr(
			handle_, 
			SQL_ATTR_AUTOCOMMIT,
			&value,
			sizeof( value),
			&dummyLen),
		*this);
	return value != 0;
}

} // namespace odbc